/*
 * @Author: GYM-png 480609450@qq.com
 * @Date: 2024-10-12 22:14:23
 * @LastEditors: GYM-png 480609450@qq.com
 * @LastEditTime: 2024-10-26 22:29:16
 * @FilePath: \EIDEd:\warehouse\CmdDebug\CmdDebug\UserCode\Cmd\cmd.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "cmd.h"
#include <stdio.h>
#include <stdarg.h> // 引入可变参数头文件
#include <string.h>
#include "global.h"
#include "malloc.h"
#include "system.h"
#include "FreeRTOS_CLI.h"
#include "usart_drv.h"
#define LOG_TAG "app_cmd"
static uint8_t find_parameters(const char *pcParameter, char **parameterArr);
uint8_t find_parameter_num(const char *pcParameter);



/*************************************************以下是用户代码******************************************************************** */

/**
 * @defgroup 命令函数声明 
 * {
 */
static BaseType_t system_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
static BaseType_t get_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
static BaseType_t clear_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);

/**
 * }
 */

/**
 * @defgroup FreeRTOS CLI命令组件 
 * {
 */
static const CLI_Command_Definition_t user_command[] = {
    {
    .pcCommand = "system",\
    .pcHelpString = "system:\t\t-t:get task; -r:reset mcu\r\n", \
    .pxCommandInterpreter = system_command, \
    .cExpectedNumberOfParameters = -1}, 
    {
    .pcCommand = "get",\
    .pcHelpString = "get:\t\t-t:get time\r\n", \
    .pxCommandInterpreter = get_command, \
    .cExpectedNumberOfParameters = -1},
    {
    .pcCommand = "clear",\
    .pcHelpString = "clear:\t\tclear the screen\r\n", \
    .pxCommandInterpreter = clear_command, \
    .cExpectedNumberOfParameters = 0}
};
/**
 * }
 */


static BaseType_t system_command(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString)
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
memset(pcWriteBuffer, 0, xWriteBufferLen);  
char **parameterArray = (char **)pvPortMalloc(sizeof(char *) * find_parameter_num(pcCommandString));
if (parameterArray == NULL)
{
    log_e("内存分配失败 按下Enter重试 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
if (find_parameters(pcCommandString, parameterArray) == 0)\
{
    log_w("没有找到参数, 请检查command格式 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}

    if (strstr(parameterArray[0], "t"))
    {
        const char *const pcHeader = "    状态   优先级   堆栈     #\r\n************************************************\r\n";
        BaseType_t xSpacePadding;
        ( void ) pcCommandString;
        ( void ) xWriteBufferLen;
        configASSERT( pcWriteBuffer );
        strcpy( pcWriteBuffer, "任务" );
        pcWriteBuffer += strlen( pcWriteBuffer );
        configASSERT( configMAX_TASK_NAME_LEN > 3 );
        for( xSpacePadding = strlen( "任务" ); xSpacePadding < ( configMAX_TASK_NAME_LEN - 3 ); xSpacePadding++ )
        {
            *pcWriteBuffer = ' ';
            pcWriteBuffer++;
            *pcWriteBuffer = 0x00;
        }
        strcpy( pcWriteBuffer, pcHeader );
        vTaskList( pcWriteBuffer + strlen( pcHeader ) );
    }
    else if (strstr(parameterArray[0], "m"))
    {
        mem_print();
    }
    else if(strstr(parameterArray[0], "r"))
    {
        log_i("系统即将重启\r\n");
        vTaskDelay(1000); // 1s后重启
        HAL_NVIC_SystemReset();
    }
    else
    {
        log_w("不支持该参数 \r\n");
    }


vPortFree(parameterArray);
return pdFALSE;
}



uint8_t out_log_buf[100] = {0};
static BaseType_t get_command( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
memset(pcWriteBuffer, 0, xWriteBufferLen);  
char **parameterArray = (char **)pvPortMalloc(sizeof(char *) * find_parameter_num(pcCommandString));
if (parameterArray == NULL)
{
    log_e("内存分配失败 按下Enter重试 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
if (find_parameters(pcCommandString, parameterArray) == 0)\
{
    log_w("没有找到参数, 请检查command格式 \r\n");
    vPortFree(parameterArray);
    return pdFALSE;
}
    if (strstr(parameterArray[0], "t"))
    {
        log_v("当前系统时间:\r\n");
        log_v("%04d年%02d月%02d日 %02d:%02d:%02d", rtc_date.Year + 2000, rtc_date.Month, rtc_date.Date, rtc_time.Hours, rtc_time.Minutes, rtc_time.Seconds);
    }
    if (strstr(parameterArray[0], "log"))
    {
        uint16_t res = 0;
        res = elog_port_get_ringbuffer(out_log_buf, 1024);
        if (res > 0)
            uart_print_fast(1 ,"\r\n%s\r\n", out_log_buf);
        else
            log_w("log empty");
    }
    
vPortFree(parameterArray);
return pdFALSE;
}

static BaseType_t clear_command( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
pcWriteBuffer[0] = '\0';  
    log_v("\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n ");

return pdFALSE;
}


/*************************************************以下是内部调用函数******************************************************************** */

/**
 * @brief 用户命令初始化
 *        在任务调度开始之前使用
 * @param  
 */
void cmd_init(void)
{
    for (uint8_t i = 0; i < sizeof(user_command)/sizeof(user_command[0]); i++)
    {
        FreeRTOS_CLIRegisterCommand( &user_command[i] );	
    }
}


/**
 * @brief 提取参数放入字符串数组
 * @param pcCommandString 整个参数字符串
 * @param parameterArr 字符串数组，存放提取出的参数
 * @return 找到的参数个数
 */
static uint8_t find_parameters(const char *pcCommandString, char **parameterArr)
{
    uint8_t len = strlen(pcCommandString);
    uint8_t found_num = 0;
    uint8_t parameter_num = 0;//总参数数量
    for (uint8_t i = 0; i < len - 1; i++)//寻找参数总数量 
    {
        if (pcCommandString[i] == ' ' && pcCommandString[i + 1] != ' ')
        {
            parameter_num++;
        }
    }
    if (parameter_num == 0)
    {
        return 0;
    }
    
    uint8_t *index = (uint8_t*) pvPortMalloc(sizeof(uint8_t) * (parameter_num + 1));  // 增加一个元素用于最后一个参数
    if (index == NULL)
    {
        return 0;
    }

    // 找到参数位置
    for (uint8_t i = 0; i < len - 1; i++)
    {
        if (found_num % 2 == 0)
        {
            if (pcCommandString[i] == ' ' && pcCommandString[i + 1] == '-')
            {
                index[found_num++] = i + 2;
                if (found_num == parameter_num)
                    break;
            }
        }
        else
        {
            if (pcCommandString[i] == ' ' && pcCommandString[i + 1] != ' ')
            {
                index[found_num++] = i + 1;
                if (found_num == parameter_num)
                    break;
            }
        }
    }

    // 提取处理参数
    for (uint8_t i = 0; i < found_num; i++)
    {
        uint8_t start = index[i];
        uint8_t end = 0;
        if (i % 2 == 0)
            end = (i + 1 < found_num) ? index[i + 1] - 1: len;  // 确保最后一个参数处理正确
        else
            end = (i + 1 < found_num) ? index[i + 1] - 2: len;  // 确保最后一个参数处理正确
        uint8_t param_len = end - start;

        parameterArr[i] = (char *)pvPortMalloc(param_len + 1);  // 分配内存
        if (parameterArr[i] == NULL)//错误处理
        {
            for (uint8_t j = 0; j < i; j++)
            {
                vPortFree(parameterArr[j]);
            }
            vPortFree(index);
            return 0;
        }
        memcpy(parameterArr[i], pcCommandString + start, param_len);
        parameterArr[i][param_len] = '\0';  // 添加字符串结束符 避免乱码
    }

    vPortFree(index);
    return found_num;
}

/**
 * @brief 寻找参数总数量
 * @param pcCommandString 命令字符串
 * @return 参数数量
 */
static uint8_t find_parameter_num(const char *pcCommandString)
{
    uint8_t len = strlen(pcCommandString);
    uint8_t parameter_num = 0;
    for (uint8_t i = 0; i < len - 1; i++)
    {
        if (pcCommandString[i] == ' ' && pcCommandString[i + 1] != ' ')
        {
            parameter_num++;
        }
    }
    return parameter_num;
}
